int i2cadr = 0x3e;
byte contrast = LCD_CONTRAST; // 0-63 5V系だとかなり少なくする
static byte iconarrow = 0;  // 上下矢印アイコン用

void lcd_cmd(byte x)
{
  Wire.beginTransmission(i2cadr);
  Wire.write(0x00);
  Wire.write(x);
  Wire.endTransmission();
}

void lcd_data(byte x)
{
  Wire.beginTransmission(i2cadr);
  Wire.write(0x40);
  Wire.write(x);
  Wire.endTransmission();
}

void lcd_puts(const char *s)
{
  while(*s) lcd_data(*s++);
}

void lcd_clear()
{
  lcd_cmd(0x01);
}

void lcd_setline(byte line) // line = 1 or 2
{
  lcd_setcursor(0,line-1);
}

void lcd_setcursor(byte pos) { // change cursor position of LCD
  lcd_cmd(0x80 | pos);
  delayMicroseconds(30);
}

void lcd_setcursor(byte col, byte row) {  
  row = min(row,1);
  col = min(col, 15);
  byte addr = col + row * 0x40;      // Why 0x40? RAM in this controller has many more bytes than are displayed.  In particular, the start of the second line (line 1 char 0) is 0x40 in DDRAM. The bytes between 0x0F (last char of line 1) and 0x40 are not displayable (unless the display is placed in marquee scroll mode)
  lcd_setcursor(addr);
}

void lcd_icon(word icon, byte onoff)
{
  switch(icon)
  {
    case ANTENNA:
    case TEL:
    case SOUND:
    case REC:
    case LOCK:
    case MUTE:
    case EXEC:
    case BATTERY:
    case BATFULL:
    case BATMID:
    case BATLOW:
//    case BATEMPTY: // same value as BATTERY, declare for easy code reading
      if (onoff == OFF)
        lcd_icon_low((byte)((icon & 0x0f00) >> 8), 0x00);
      else
        lcd_icon_low((byte)((icon & 0x0f00) >> 8), (byte)(icon & 0x00ff));
      break;
    case UPARROW:
    case DOWNARROW:
      if (onoff == OFF)
      {
        iconarrow &= ~(byte)(icon & 0x00ff);
        lcd_icon_low((byte)((icon & 0x0f00) >> 8), iconarrow);
      }
      else
      {
        iconarrow |= (byte)(icon & 0x00ff);
        lcd_icon_low((byte)((icon & 0x0f00) >> 8), iconarrow);
      }
      break;
      
  }
}

void lcd_icon_low(byte add, byte x)
{
  lcd_cmd(0x39);
  lcd_cmd(0x40 | (0x0f & add));
  lcd_data(x);
  lcd_cmd(0x38);
  lcd_cmd(0x80);
}

void lcd_icon_clear()
{
  byte add;
  for(add = 0; add <= 0x0f; add++)
    lcd_icon_low(add, 0x00);
}

void lcd_init()
{
  // reset
  // LCD initialize
  delay(40);
  Wire.begin();
  lcd_cmd(0x38); // function set
  lcd_cmd(0x39); // function set
  lcd_cmd(0x14); // interval osc
  lcd_cmd(0x70 | (contrast & 15)); // contrast low
  lcd_cmd(0x5c | (contrast >> 4 & 3)); // contrast high / icon / power
//  lcd_cmd(0x58 | (contrast >> 4 & 3)); // contrast high / icon / power
  lcd_cmd(0x6c); // follower control
  delay(300);
  lcd_cmd(0x38); // function set
  lcd_cmd(0x0c); // display on
  lcd_cmd(0x01); // clear display
  delay(2);
  lcd_icon_clear(); // clear all icon
}

void lcd_move(byte pos){
  lcd_cmd(0x80 | pos);
}

void lcd_icon_display_test()
{
  int interval = 500;
  lcd_icon(ANTENNA,ON);
  delay(interval);
  lcd_icon(ANTENNA,OFF);
  delay(interval);
  lcd_icon(TEL,ON);
  delay(interval);
  lcd_icon(TEL,OFF);
  delay(interval);
  lcd_icon(SOUND,ON);
  delay(interval);
  lcd_icon(SOUND,OFF);
  delay(interval);
  lcd_icon(REC,ON);
  delay(interval);
  lcd_icon(REC,OFF);
  delay(interval);
  lcd_icon(UPARROW,ON);
  delay(interval);
  lcd_icon(DOWNARROW,ON);
  delay(interval);
  lcd_icon(UPARROW,OFF);
  delay(interval);
  lcd_icon(DOWNARROW,OFF);
  delay(interval);
  lcd_icon(LOCK,ON);
  delay(interval);
  lcd_icon(LOCK,OFF);
  delay(interval);
  lcd_icon(MUTE,ON);
  delay(interval);
  lcd_icon(MUTE,OFF);
  delay(interval);
  lcd_icon(BATTERY,ON);
  delay(interval);
  lcd_icon(BATTERY,OFF);
  delay(interval);
  lcd_icon(BATFULL,ON);
  delay(interval);
  lcd_icon(BATFULL,OFF);
  delay(interval);
  lcd_icon(BATMID,ON);
  delay(interval);
  lcd_icon(BATMID,OFF);
  delay(interval);
  lcd_icon(BATLOW,ON);
  delay(interval);
  lcd_icon(BATLOW,OFF);
  delay(interval);
  lcd_icon(BATEMPTY,ON);
  delay(interval);
  lcd_icon(BATEMPTY,OFF);
  delay(interval);
  lcd_icon(EXEC,ON);
  delay(interval);
  lcd_icon(EXEC,OFF);
  delay(interval);
}
